﻿using System;
using Tiny.Imaging.Filter.PixelLibrary;

namespace Tiny.Imaging.Filter.PointFilter
{
    public class HueShiftFilter : BaseFilter.BaseFilter
    {
        private readonly int _degree;
        private float EPSILON = 1e-7f;

        public HueShiftFilter(int degree = 0, Func<int, int, int> blend = null, int opacity = 100)
            : base(blend, opacity)
        {
            _degree = degree;
        }

        public override int Process(Rgba rgba)
        {
            int max = Math.Max(rgba.R, Math.Max(rgba.G, rgba.B));
            int min = Math.Min(rgba.R, Math.Min(rgba.G, rgba.B));
            float c = max - min;
            float h = 0;

            if (Math.Abs(c - 0f) < EPSILON)
            {
                return rgba.ToInteger();
            }

            if (max == rgba.R)
            {
                h = (60f * ((rgba.G - rgba.B) / c % 6) + _degree) / 60f;
            }
            else if (max == rgba.G)
            {
                h = (60f * ((rgba.B - rgba.R) / c + 2) + _degree) / 60f;
            }
            else
            {
                h = (60f * ((rgba.R - rgba.G) / c + 4) + _degree) / 60f;
            }

            float x = c * (1 - Math.Abs(h % 2 - 1));

            Rgba result = new Rgba { R = rgba.R, G = rgba.G, B = rgba.B, A = rgba.A };
            if (0 <= h && h < 1)
            {
                result.R = MathLibrary.MathLibrary.Clamp(c + min);
                result.G = MathLibrary.MathLibrary.Clamp(x + min);
                result.B = min;
            }
            else if (1 <= h && h < 2)
            {
                result.R = MathLibrary.MathLibrary.Clamp(x + min);
                result.G = MathLibrary.MathLibrary.Clamp(c + min);
                result.B = min;
            }
            else if (2 <= h && h < 3)
            {
                result.R = min;
                result.G = MathLibrary.MathLibrary.Clamp(c + min);
                result.B = MathLibrary.MathLibrary.Clamp(x + min);
            }
            else if (3 <= h && h < 4)
            {
                result.R = min;
                result.G = MathLibrary.MathLibrary.Clamp(x + min);
                result.B = MathLibrary.MathLibrary.Clamp(c + min);
            }
            else if (4 <= h && h < 5)
            {
                result.R = MathLibrary.MathLibrary.Clamp(x + min);
                result.G = min;
                result.B = MathLibrary.MathLibrary.Clamp(c + min);
            }
            else if (5 <= h && h < 6)
            {
                result.R = MathLibrary.MathLibrary.Clamp(c + min);
                result.G = min;
                result.B = MathLibrary.MathLibrary.Clamp(x + min);
            }

            return BlendRgba(rgba, result).ToInteger();
        }
    }
}